package com.bleeth.flow.core.util;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.ClassScanner;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.JarClassLoader;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.setting.Setting;
import com.bleeth.flow.core.common.APlugin;
import com.bleeth.flow.core.common.PluginAnnotation;
import com.bleeth.flow.core.common.PluginTypeEnum;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author ：Bleeth
 * @date ：2021-08-06
 * @description：组件相关工具类
 */
public class PluginUtil {

    public static final String PLUGIN_ROOT_PATH = System.getProperty("user.dir") + "/plugins";

    private static Map<String, APlugin> pluginMap = new ConcurrentHashMap();


    /**
     * 扫描系统插件
     */
    private static void scanSystemPlugin() {
        Set<Class<?>> pluginClass = ClassScanner.scanPackageBySuper("com.bleeth.flow", APlugin.class);
        for (Class<?> itemPlugin : pluginClass) {
            APlugin aPlugin = parseClass(itemPlugin);
            if (aPlugin == null) {
                continue;
            }
            pluginMap.put(aPlugin.getId(), aPlugin);
        }
    }

    /**
     * 扫描第三方外置插件
     */
    public static void scanPathPlugin() {
        File dir = new File(PLUGIN_ROOT_PATH);
        File[] pluginDirFileList = dir.listFiles();
        if (pluginDirFileList == null || pluginDirFileList.length == 0) {
            return;
        }
        for (int i = 0; i < pluginDirFileList.length; i++) {
            File pluginDirFile = pluginDirFileList[i];
            if (!pluginDirFile.isDirectory()) {
                continue;
            }
            List<File> pluginFileList = FileUtil.loopFiles(pluginDirFile);
            List<File> settingFileList = pluginFileList.stream().filter(file -> file.getName().equals("plugin.setting")).collect(Collectors.toList());
            if (CollUtil.isEmpty(settingFileList)) {
                continue;
            }
            File settingFile = settingFileList.get(0);
            Setting setting = new Setting(settingFile.getPath());
            String pluginClass = setting.getStr("pluginClass");
            JarClassLoader loader = JarClassLoader.load(pluginDirFile);
            Class<?> aClass = null;
            try {
                aClass = loader.loadClass(pluginClass);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

            if (aClass != null) {
                PluginAnnotation annotation = AnnotationUtil.getAnnotation(aClass, PluginAnnotation.class);
                if (annotation == null) {
                    return ;
                }
                String annName = annotation.name();
                String annId = annotation.id();
                String annDescription = annotation.description();
                PluginTypeEnum annType = annotation.type();
                JSONObject object = new JSONObject();
                object.set("id", annId);
                object.set("name", annName);
                object.set("description", annDescription);
                object.set("type", annType.name());
                Class<APlugin> b  =  (Class<APlugin>)aClass;
                APlugin plugin = object.toBean(b);
                if(aClass!=null){
                    System.err.println("path class load success");
                    System.err.println(plugin);
                    pluginMap.put(plugin.getId(), plugin);
                }
            }
        }
    }

    private static APlugin parseClass(Class<?> itemPlugin) {
        PluginAnnotation annotation = AnnotationUtil.getAnnotation(itemPlugin, PluginAnnotation.class);
        if (annotation == null) {
            return null;
        }
        String annName = annotation.name();
        String annId = annotation.id();
        String annDescription = annotation.description();
        PluginTypeEnum annType = annotation.type();
        Class<APlugin> clazz = ClassUtil.loadClass(itemPlugin.getName());
        JSONObject object = new JSONObject();
        object.set("id", annId);
        object.set("name", annName);
        object.set("description", annDescription);
        object.set("type", annType.name());

        APlugin plugin = object.toBean(clazz);
        return plugin;
    }


    public static Map<String, APlugin> getPluginMap() {
        if (pluginMap.isEmpty()) {
            scanSystemPlugin();
            scanPathPlugin();
        }
        if (pluginMap.isEmpty()) {
            Console.error("扫描系统插件,未找到任何插件");
        }
        return pluginMap;
    }

    public static Map<PluginTypeEnum, List<APlugin>> getPluginMapByType() {
        if (pluginMap.isEmpty()) {
            scanSystemPlugin();
        }
        if (pluginMap.isEmpty()) {
            Console.error("扫描系统插件,未找到任何插件");
        }
        Map<PluginTypeEnum, List<APlugin>> typeMap = new HashMap<>();
        pluginMap.entrySet().stream().forEach(entry -> {
            String id = entry.getKey();
            APlugin plugin = entry.getValue();
            String type = plugin.getType();
            PluginTypeEnum pluginType = PluginTypeEnum.valueOf(type);
            if (typeMap.containsKey(pluginType)) {
            } else {
                typeMap.put(pluginType, CollUtil.newArrayList());
            }
            typeMap.get(pluginType).add(plugin);
        });
        return typeMap;
    }
}
